package core.domain.query.expgen;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

import core.domain.IdEntity;
import core.domain.util.DomainUtils;

public abstract class JpaSearchExpGenerator<T extends IdEntity> implements
		IJpaSearchExpGenerator {

	private EntityManager em;

	private Root<?> root;

	private Object bean;

	private Class<T> actualClass;

	private List<Predicate> preList;

	public JpaSearchExpGenerator(Object bean) {
		super();
		this.bean = bean;
		this.preList = new ArrayList<Predicate>();
	}

	public EntityManager getEm() {
		return em;
	}

	public Object getBean() {
		return bean;
	}

	public void setBean(Object bean) {
		this.bean = bean;
	}

	public void setEm(EntityManager em) {
		this.em = em;
	}

	public void setActualClass(Class<T> actualClass) {
		this.actualClass = actualClass;
	}

	public void setRoot(Root<?> root) {
		this.root = root;
	}

	public void addPredicate(Predicate predicate) {
		preList.add(predicate);
	}

	public Predicate generate(CriteriaBuilder builder, CriteriaQuery<?> query,
			EntityManager em) {
		this.setEm(em);

		preList.clear();

		setRoot(query.from(getActualClass()));

		Predicate pre = null;

		for (Predicate predic : preList) {
			if (pre == null) {
				pre = predic;
			} else {
				pre = builder.and(pre, predic);
			}
		}
		return pre;
	}

	@SuppressWarnings("unchecked")
	public Class<T> getActualClass() {
		if (this.actualClass == null) {
			this.actualClass = (Class<T>) DomainUtils
					.getSingleParameterClass(getClass());
		}
		return this.actualClass;
	}

	public List<Selection<?>> getSelectField(CriteriaBuilder cb, Root<?> root) {
		return null;
	}

	public Boolean getDistinctable() {
		return false;
	}

	public Root<?> getRoot() {
		return this.root;
	}

	public List<Predicate> getPredicates() {
		return null;
	}

	public List<Expression<?>> getGroupBy(CriteriaBuilder cb) {
		return null;
	}

	public List<Order> getOrderBy(CriteriaBuilder builder) {
		return null;
	}

	public List<Predicate> having(CriteriaBuilder cb) {
		return null;
	}

	public Map<String, Object> getQueryHints() {
		return null;
	}
}
